package org.tri.entity;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Formula;

/**
 * La clase {@code AbstractCompra} representa una compra realizada por
 * un establecimiento. Esta clase sirve de base para mentener registro
 * de compras actuales y compras consideradas "históricas". Esta clase contempla
 * tanto las compras de carvanas para animales nacidos en el establecimiento
 * como las compras de animales a otro productor.
 * @author kiira
 * @version 1.0, Nov 23, 2011
 */
@MappedSuperclass
public abstract class AbstractCompra implements Serializable, Transaccion {

    /** Identificador único del objeto. */
    private int idCompra;
    /** Fecha en la que se realizo la compra. */
    private Date fecha;
    /** Establecimiento que realizó la compra. */
    private Establecimiento establecimiento;
    /** Número de la factura correspondiente a la compra. */
    private long nroFactura;
    /** Tipo de la factura correspondiente a la compra. */
    private String tipoFactura;
    /** Nro de DTA correspondiente al establecimiento de origen de los animales*/
    private long dtaOrigen;
    /** Nro de Renspa correspondiente al establecimiento de origen de los animales*/
    private long renspaOrigen;
    /** Da la cantidad de animales asociados a la compra*/
    private int cantidadAnimales;

    /**
     * Nos devuelve el identificador de la compra utilizado por Hibernate 
     * para identificar la misma.
     * @return int identificador de la compra
     */
    @Id
    @GeneratedValue ( strategy = GenerationType.IDENTITY )
    @Column ( name = "id_compra", nullable = false )
    public int getIdCompra() {
        return idCompra;

    }//end método getIdCompra

    /**
     * Nos permite modificar el identificador de la compra utilizado por 
     * Hibernate. 
     * Este método es de uso exclusivo de Hibernate.
     * @param id int identificador de la compra
     */
    protected void setIdCompra( int id ) {
        idCompra = id;

    }//end método setIdCompra

    /**
     * Nos devuelve la fecha en la cual fue realizada una compra.
     * @return Date fecha de realización de la compra
     */
    @Temporal ( javax.persistence.TemporalType.DATE )
    @Column ( name = "fecha", nullable = false )
    public Date getFecha() {
        return fecha;

    }//end método getFecha

    /**
     * Nos permite modificar la fecha de realización de una compra.
     * @param fecha Date fecha de realización de la compra
     */
    public void setFecha( Date fecha ) {
        this.fecha = fecha;

    }//end método setFecha

    /**
     * Nos devuelve el número de factura de una compra
     * @return long número de factura
     */
    @Column ( name = "nro_factura" )
    public long getNroFactura() {
        return nroFactura;

    }//end método getNroFactura

    /**
     * Nos permite modificar el número de factura de una compra realizada
     * @param nroFactura long número de factura
     */
    public void setNroFactura( long nroFactura ) {
        this.nroFactura = nroFactura;

    }//end método setNroFactura

    /**
     * Nos devuelve el tipo de factura de una compra realizada
     * @return char tipo de factura
     */
    @Column ( name = "tipo_factura" )
    public String getTipoFactura() {
        return tipoFactura;

    }//end método getTipoFactura

    /**
     * Nos permite modificar el tipo de factura de una compra
     * @param tipoFactura char tipo de factura
     */
    public void setTipoFactura( String tipoFactura ) {
        this.tipoFactura = tipoFactura;

    }//end método setTipoFactura

    /**
     * Nos devuelve los datos del establecimiento que realizó una compra.
     * @return Establecimiento datos del establecimiento
     */
    @ManyToOne ( cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, 
                 optional = false )
    @JoinColumn ( name = "establecimiento" )
    @Cascade ( org.hibernate.annotations.CascadeType.SAVE_UPDATE )
    public Establecimiento getEstablecimiento() {
        return establecimiento;

    }//end método getEstablecimiento

    /**
     * Nos permite modificar el establecimiento que realizó la compra.
     * @param establecimiento Establecimiento nuevo establecimiento
     */
    public void setEstablecimiento( Establecimiento establecimiento ) {
        this.establecimiento = establecimiento;

    }//end método setEstablecimiento
    
    /**
     * Nos devuelve el numero de DTA asociado al TRI correspondiente a la compra
     * de los animales.
     * @return long Dta asociado a la compra
     */
    @Column ( name = "dta_origen" )
    public long getDtaOrigen(){
        return dtaOrigen;
        
    }//end método getDtaOrigen
    
    /**
     * Nos permite modificar el DTA asociado al TRI correspondiente a la compra
     * de los animales.
     * @param dtaOrigiante long Dta asociado a la compra
     */
    public void setDtaOrigen ( long dtaOrigen){
        this.dtaOrigen = dtaOrigen;
        
    }//end método setDtaOriginante
    
    /**
     * Nos devuelve el nro de Renspa del establecimiento de donde provienen los
     * animales comprados
     * @return long Renspa del establecimiento de origen
     */
    @Column ( name = "renspa_origen")
    public long getRenspaOrigen(){
        return renspaOrigen;
        
    }//end método getRenspaOrigen
    
    /**
     * Nos permite modificar el Renspa del establecimiento de donde proienen los 
     * animales comprados.
     * @param renspaOrigen long Renspa del establecimiento de origen
     */
    public void setRenspaOrigen ( long renspaOrigen ){
        this.renspaOrigen = renspaOrigen;
        
    }//end método setRenspaOrigen
    
    /**
     * Devuelva la cantidad de animales asociados a la compra.
     * @return cantidad de animales asociados a la compra.
     */
    @Basic ( fetch = FetchType.LAZY )
    @Formula ( "(SELECT COUNT(a.id_animal) "
            + "FROM animal a "
            + "WHERE a.compra = id_compra) + "
            + "(SELECT COUNT(ah.id_animal) "
            + "FROM animal_hist ah "
            + "WHERE ah.compra = id_compra "
            + "OR ah.compra_hist = id_compra)" )
    public int getCantidadAnimales() {
        return this.cantidadAnimales;

    }//end método getCantidadAnimales

    /**
     * Método utilizado por Hibernate para asignar la cantidad de animales.
     * @param cantidad cantidad de animales de la compra.
     */
    protected void setCantidadAnimales( int cantidad ) {
        this.cantidadAnimales = cantidad;

    }//end método setCantidadAnimales

    /**
     * Indica si esta compra es igual a otro objeto pasado por parámetros.
     * Si el otro objeto se trata de un {@code AbstractCompra} como este,
     * se los considera iguales cuando sus propiedades son iguales.
     * @param obj objeto con el cual comparar.
     * @return <li>true si los objetos son equivalentes. 
     *         <li>flase si los objetos no son equivalentes.
     */
    @Override
    public boolean equals( Object obj ) {
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        final AbstractCompra other = (AbstractCompra)obj;
        if ( this.fecha != other.fecha && ( this.fecha == null || !this.fecha.equals( other.fecha ) ) )
            return false;
        if ( this.establecimiento != other.establecimiento && ( this.establecimiento == null || !this.establecimiento.equals( other.establecimiento ) ) )
            return false;
        if ( this.nroFactura != other.nroFactura )
            return false;
        if ( this.tipoFactura != other.tipoFactura )
            return false;
        return true;
        
    }//end método equals

    /**
     * Devuelve la computación de un número a partir de las propiedades de la
     * compra,para que el mismo pueda ser insertado en un {@code Set} sin 
     * peligro de que se produzcan inconsistencia en los datos.
     * @return código hash del objeto.
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 29 * hash + ( this.fecha != null ? this.fecha.hashCode() : 0 );
        hash = 29 * hash + ( this.establecimiento != null ? this.establecimiento.hashCode() : 0 );
        hash = 29 * hash + (int)( this.nroFactura ^ ( this.nroFactura >>> 32 ) );
        hash = 29 * hash + (this.tipoFactura != null ? this.tipoFactura.hashCode() : 0 );
        return hash;
        
    }//end método hashCode
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Date obtenerFecha() {
        return getFecha();
        
    }//end método obtenerFecha
    
    /**
     * {@inheritDoc}
     */
    @Override
    public String obtenerTipoMovimiento() {
        return "Compra";
        
    }//end método obtenerTipoMovimiento
    
    /**
     * {@inheritDoc}
     */
    @Override
    public long obtenerNroComprobante() {
        long comprobante;
        
        if ( getNroFactura() != 0 )
            comprobante = getNroFactura();
        else
            comprobante = getDtaOrigen();
        
        return comprobante;
        
    }//end método obtenerNroComprobante
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Establecimiento obtenerEstablecimiento() {
        return getEstablecimiento();
        
    }//end método obtenerEstablecimiento
    
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean esEntrada() {
        return true;
        
    }//end método esEntrada
    
    /**
     * {@inheritDoc}
     */
    @Override
    public int obtenerCantidadAnimales(){
        return getCantidadAnimales();
    }

}//end clase AbstractCompra

